package com.umeox.watch.moto.dataservice.receiver;


import android.annotation.SuppressLint;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.SystemClock;

import com.umeox.moto.common.log.Logger;
import com.umeox.moto.common.utils.DateUtils;
import com.umeox.watch.moto.dataservice.DataProvider;
import com.umeox.watch.moto.dataservice.base.BaseApp;
import com.umeox.watch.moto.dataservice.base.LauncherManager;
import com.umeox.watch.moto.dataservice.constants.Constants;
import com.umeox.watch.moto.dataservice.constants.InternalConstant;
import com.umeox.watch.moto.dataservice.db.model.ForbidPeriods;
import com.umeox.watch.moto.dataservice.services.ApiService;

import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Random;

public class AlarmReceiver extends BroadcastReceiver {

    private LauncherManager mLauncherManager;

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        Logger.i("AlarmReceiver Broadcast : " + action);
        mLauncherManager = LauncherManager.getInstance();
        if (InternalConstant.ACTION_ENABLE_STUDY_MODE_ALARM.equals(action)) {
            Logger.i("收到启用上课模式闹钟，计算关闭上课模式闹钟");
            sendBroadcast2DisableFeatures(context);
            //收到"启用上课模式"闹钟，重置闹钟为"关闭上课模式"
            updateStudyModeAlarm(context, false, false);
        } else if (InternalConstant.ACTION_DISABLE_STUDY_MODE_ALARM.equals(action)) {
            Logger.i("收到关闭上课模式闹钟，计算下次开启上课模式闹钟");
            sendBroadcast2EnableFeatures(context);
            //收到"禁用上课模式"闹钟，重置闹钟为"启用上课模式"
            updateStudyModeAlarm(context, true, false);
        } else {
            if (InternalConstant.ACTION_RESET_STUDY_MODE_ALARM.equals(action)) {
                Logger.i("重置上课模式闹钟");
                final ForbidPeriods forbidPeriods = mLauncherManager.getForbidPeriods();
                if (LauncherManager.getInstance().isActivated() && forbidPeriods != null && forbidPeriods.isAvalid()) {
                    if (forbidPeriods.enableNow()) {
                        Logger.i("当前在禁用时段内，发送广播开启上课模式，并且设置关闭上课模式闹钟");
                        sendBroadcast2DisableFeatures(context);
                        updateStudyModeAlarm(context, false, false);
                    } else {
                        sendBroadcast2EnableFeatures(context);
                        Logger.i("设置下次开启上课模式闹钟");
                        updateStudyModeAlarm(context, true, false);
                    }
                } else {
                    Logger.i("当前没有设置禁用时段，取消已设置的闹钟");
                    sendBroadcast2EnableFeatures(context);

                    updateStudyModeAlarm(context, true, true);
                    updateStudyModeAlarm(context, false, true);
                }
            } else if (InternalConstant.ACTION_UPLOAD_STEP_ALARM.equals(action)) {
                Logger.i("上报记步值");
                if (BaseApp.isActivated()) {
                    ApiService.uploadStepInfo(DataProvider.getStepsToday());
                    updateUploadStepAlarm(context);
                } else {
                    cancelUploadStepAlarm(context);
                }
            } else if (InternalConstant.ACTION_CANCEL_ALL.equals(action)) {
                //解绑设备的时候调用这里
                //取消上报计步闹钟
                cancelUploadStepAlarm(context);
                //取消正在运行的上课模式的闹钟
                updateStudyModeAlarm(context, true, true);//取消启用上课模式的闹钟
                sendBroadcast2EnableFeatures(context);
                updateStudyModeAlarm(context, false, true);//取消停止上课模式的闹钟
            }
        }
    }

    /**
     * @param mss 要转换的毫秒数
     * @return 该毫秒数转换为days:hours:minutes:seconds 后的格式
     */
    private String formatDuring(long mss) {
        String format = "%1$sd:%2$sh:%3$sm:%4$ss";
        long days = mss / (1000 * 60 * 60 * 24);
        long hours = (mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
        long minutes = (mss % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (mss % (1000 * 60)) / 1000;
        return String.format(Locale.getDefault(), format, days, hours, minutes, seconds);
    }

    /**
     * 接收到开启上课模式广播，需要计算下次禁用上课模式的时间
     * 禁用时段会出现重叠的时刻，比如某个时段为 08:00-10:00与下一个时段 10:00-11:00就会出现上个时段的结束点与下个时段的开始点重叠
     * 所以在计算闹钟时间的时候，把这两个时段当成一个处理，最后合并成 08:00-11:00
     */
    private long getNextTime4DisableStudyMode() {
        List<ForbidPeriods.Period> forbidPeriods = mLauncherManager.getForbidPeriods().getPeriods();

        if (forbidPeriods == null || forbidPeriods.isEmpty()) {
            Logger.w("无效的禁用时段设置->" + forbidPeriods);
            return -1;
        }

        Logger.w("原始时段列表:" + forbidPeriods);
        //根据时段开始时间升序排列
        Collections.sort(forbidPeriods);

        long realNextTime = -1;
        //精确到分钟比较，有可能两个时段的其中一个的结束时间等于下一个时段的开始时间，所以在比较时间的时候，用小于等于
        Calendar now = Calendar.getInstance();
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);

        Calendar time4Enable = Calendar.getInstance();

        //迭代时段数组，合并相同的时段，比较出距现在最接近的禁用开启时间
        for (int i = 0; i < forbidPeriods.size(); i++) {
            ForbidPeriods.Period period = forbidPeriods.get(i);
            //判断下一个元素是否存在
            if (i + 1 < forbidPeriods.size()) {
                ForbidPeriods.Period nextPeriod = forbidPeriods.get(i + 1);
                //对比相邻两个元素，合并相同的时段
                if (period.getEndTimeInMillis() == nextPeriod.getStartTimeInMillis()) {
                    period.setEndTimeInMillis(nextPeriod.getEndTimeInMillis());
                    forbidPeriods.remove(nextPeriod);
                }
            }

            time4Enable.setTimeInMillis(period.getEndTimeInMillis());

            long nextTime = -1;
            if (now.compareTo(time4Enable) <= 0) {
                nextTime = time4Enable.getTimeInMillis();
            }

            if (realNextTime == -1 && nextTime > -1) {
                realNextTime = nextTime;//第一次赋值
            } else if (realNextTime > -1 && nextTime > -1 && nextTime < realNextTime) {
                realNextTime = nextTime;//两者间取最小值即最近的一个时间
            }
        }
        return realNextTime;
    }

    /**
     * 接收到禁用上课模式广播，获取下次开启上课模式的时间
     */
    private long getNextTime4EnableStudyMode() {
        List<ForbidPeriods.Period> forbidPeriods = mLauncherManager.getForbidPeriods().getPeriods();

        if (forbidPeriods == null || forbidPeriods.isEmpty()) {
            Logger.w("无效的禁用时段设置->" + forbidPeriods);
            return -1;
        }

        Logger.i("原始时段列表:" + forbidPeriods);
        //根据时段开始时间升序排列
        Collections.sort(forbidPeriods);

        long realNextTime = -1;
        //精确到分钟比较，有可能两个时段的其中一个的结束时间等于下一个时段的开始时间，所以在比较时间的时候，用小于等于
        Calendar now = Calendar.getInstance();
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);

        Calendar time4Disable = Calendar.getInstance();

        //迭代时段数组，合并相同的时段，比较出距现在最接近的禁用开启时间
        for (int i = 0; i < forbidPeriods.size(); i++) {
            ForbidPeriods.Period period = forbidPeriods.get(i);
            //判断下一个元素是否存在
            if (i + 1 < forbidPeriods.size()) {
                ForbidPeriods.Period nextPeriod = forbidPeriods.get(i + 1);
                //对比相邻两个元素，合并相同的时段
                if (period.getEndTimeInMillis() == nextPeriod.getStartTimeInMillis()) {
                    period.setEndTimeInMillis(nextPeriod.getEndTimeInMillis());
                    forbidPeriods.remove(nextPeriod);
                }
            }
            time4Disable.setTimeInMillis(period.getStartTimeInMillis());

            long nextTime = -1;
            if (now.compareTo(time4Disable) <= 0) {
                nextTime = time4Disable.getTimeInMillis();
            }

            if (realNextTime == -1 && nextTime > -1) {
                realNextTime = nextTime;//第一次赋值
            } else if (nextTime > -1 && nextTime < realNextTime) {
                realNextTime = nextTime;//两者间取最小值即最近的一个时间
            }
        }
        return realNextTime;
    }

    /**
     * 设置或者取消上课模式闹钟
     *
     * @param enableClassMode true启用上课模式，false 禁用上课模式
     * @param cancelAlarm     设置或取消者闹钟
     */
    private void updateStudyModeAlarm(Context ctx, boolean enableClassMode, boolean cancelAlarm) {
        Intent intent = new Intent(ctx, AlarmReceiver.class);
        if (enableClassMode) {
            intent.setAction(InternalConstant.ACTION_ENABLE_STUDY_MODE_ALARM);
        } else {
            intent.setAction(InternalConstant.ACTION_DISABLE_STUDY_MODE_ALARM);
        }

        AlarmManager alm = ((AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE));
        if (!cancelAlarm) {
            long time = 0;
            if (enableClassMode) {
                time = getNextTime4EnableStudyMode();
                if (time <= 0) {
                    updateStudyModeAlarm(ctx, true, true);
                    return;
                }
            } else {
                time = getNextTime4DisableStudyMode();
                if (time <= 0) {
                    updateStudyModeAlarm(ctx, false, true);
                    return;
                }
            }
            long elapsedRealtime = SystemClock.elapsedRealtime();
            long nextTime = elapsedRealtime + time - System.currentTimeMillis();
            Logger.i((enableClassMode ? "开启上课模式" : "关闭上课模式") + "时间->" + DateUtils.formatDateTime(time));

            PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, InternalConstant.REQUEST_CODE_STUDYMODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                alm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pendingIntent);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                alm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pendingIntent);
            } else {
                alm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, nextTime, pendingIntent);
            }
        } else {
            Logger.i("取消已设置的" + (enableClassMode ? "开启上课模式闹钟" : "关闭上课模式闹钟"));
            PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, InternalConstant.REQUEST_CODE_STUDYMODE, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_NO_CREATE);
            alm.cancel(pendingIntent);
        }
    }

    /**
     * 更新上报计步闹钟
     * 每隔45分~65分钟执行一次
     * 每次执行的分钟、秒钟取45~59之间随机时间点
     */
    private void updateUploadStepAlarm(Context ctx) {
        Calendar now = Calendar.getInstance();
        int hour = now.get(Calendar.HOUR_OF_DAY);
        now.set(Calendar.HOUR_OF_DAY, hour + 1);
        now.set(Calendar.MINUTE, 45);
        now.set(Calendar.SECOND, 0);
        now.set(Calendar.MILLISECOND, 0);
        long bgTime = now.getTimeInMillis();
        now.set(Calendar.MINUTE, 59);
        now.set(Calendar.SECOND, 59);
        long edTime = now.getTimeInMillis();

        Random rand = new Random();
        long nextTime = rand.nextInt((int) (edTime - bgTime)) + bgTime;
        long elapsedRealtime = SystemClock.elapsedRealtime();
        long realNextTime = elapsedRealtime + nextTime - System.currentTimeMillis();
        Logger.i("当前已开机时长->" + formatDuring(elapsedRealtime));
        Logger.i("下次上报记步数据时间->" + DateUtils.formatDateTime(nextTime) + "|" + formatDuring(realNextTime));

        Intent intent = new Intent(ctx, AlarmReceiver.class);
        intent.setAction(InternalConstant.ACTION_UPLOAD_STEP_ALARM);
        AlarmManager alm = ((AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE));
        PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, InternalConstant.REQUEST_CODE_UPOLOADSTEP, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            alm.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, realNextTime, pendingIntent);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            alm.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, realNextTime, pendingIntent);
        } else {
            alm.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, realNextTime, pendingIntent);
        }
    }

    /**
     * 取消上报计步数据闹钟
     */
    private void cancelUploadStepAlarm(Context ctx) {
        Logger.e("取消上报记步数据闹钟");
        Intent intent = new Intent(ctx, AlarmReceiver.class);
        intent.setAction(InternalConstant.ACTION_UPLOAD_STEP_ALARM);
        AlarmManager alm = ((AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE));
        PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, InternalConstant.REQUEST_CODE_UPOLOADSTEP, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_NO_CREATE);
        alm.cancel(pendingIntent);
    }

    @SuppressLint("WrongConstant")
    private void sendBroadcast2DisableFeatures(Context context) {
        DataProvider.inForbidPeriod(true);
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | Intent.FLAG_RECEIVER_FOREGROUND | InternalConstant.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.setAction(Constants.ACTION_ENABLE_FEATURES);
        context.sendBroadcast(intent);
    }

    @SuppressLint("WrongConstant")
    private void sendBroadcast2EnableFeatures(Context context) {
        DataProvider.inForbidPeriod(false);
        Intent intent = new Intent();
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | Intent.FLAG_RECEIVER_FOREGROUND | InternalConstant.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        intent.setAction(Constants.ACTION_DISABLE_FEATURES);
        context.sendBroadcast(intent);
    }
}
